﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EMGunSharp
{
    /// <summary>
    /// 线性对应表
    /// </summary>
    class LinearityMapper
    {
        Dictionary<double, double> KnownPoints;
        public double LastConfidence { private set; get; }
        /// <summary>
        /// 线性对应表
        /// <para>记录一系列点，对已知点之间使用线性数据填充</para>
        /// </summary>
        public LinearityMapper()
        {
            KnownPoints = new Dictionary<double, double>();
            KnownPoints.Add(double.MinValue, double.MinValue);
            KnownPoints.Add(double.MaxValue, double.MaxValue);
        }

        /// <summary>
        /// 添加已知点
        /// <para>更多的已知点会使查表结果更加接近实际</para>
        /// </summary>
        /// <param name="x">X</param>
        /// <param name="y">Y</param>
        public void AddPoint(double x, double y)
        {
            if (KnownPoints.ContainsKey(x))
            {
                KnownPoints[x] += y;
                KnownPoints[x] /= 2;
            }
            else
            {
                KnownPoints.Add(x, y);
                KnownPoints = KnownPoints.OrderBy(p => p.Key).ToDictionary(p => p.Key, o => o.Value);
            }
        }

        /// <summary>
        /// 查询X对应的Y
        /// <para>如果存在该已知点，则直接返回；否则线性拟合前后两最近已知点求得当前点。</para>
        /// </summary>
        /// <param name="x">X</param>
        /// <returns>对应的Y</returns>
        public double MapX2Y(double x)
        {
            if (KnownPoints.ContainsKey(x)) return KnownPoints[x];

            double lx = 0, bx = 0;
            foreach (var point in KnownPoints)
            {
                if (point.Key < x) lx = point.Key;
                if (point.Key > x)
                {
                    bx = point.Key;
                    break;
                }
            }
            double rate = (x - lx) / (bx - lx);
            LastConfidence = Math.Abs(rate - 0.5) * 2 / (bx - lx);
            double gain = (KnownPoints[bx] - KnownPoints[lx]) * rate;
            return gain + KnownPoints[lx];
        }

        /// <summary>
        /// 查询Y对应的X
        /// <para>如果存在该已知点，则直接返回；否则线性拟合前后两最近已知点求得当前点。</para>
        /// </summary>
        /// <param name="y">Y</param>
        /// <returns>对应的X</returns>
        public double MapY2X(double y)
        {
            double ly = 0, by = 0;
            double lyx = 0, byx = 0;
            foreach (var point in KnownPoints)
            {
                if (point.Value == y) return point.Key;
                if (point.Value < y)
                {
                    ly = point.Value;
                    lyx = point.Key;
                }
                if (point.Value > y)
                {
                    by = point.Value;
                    byx = point.Key;
                    break;
                }
            }
            double rate = (y - ly) / (by - ly);
            LastConfidence = Math.Abs(rate - 0.5) * 2 / (by - ly);
            double gain = (byx - lyx) * rate;
            return gain + lyx;
        }
    }
}
